package com.dx.financehy.aspect;

import cn.hutool.core.lang.UUID;
import com.dx.financehy.utils.AdminConstant;
import com.dx.financehy.utils.JsonTOUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * <pre>
 * @描述： 统一请求日志打印
 * @作者：CLD
 * @创建时间：2020/10/26 19:36
 * </pre>
 **/
@Slf4j
@Configuration
@Aspect
public class LogPrintAspect {

    /**
     * 进入方法时间戳
     */
    private Long startTime;
    /**
     * 方法结束时间戳(计时)
     */
    private Long endTime;

    /**
     * 定义一个切入点. 解释下：
     * <p>
     * <pre>
     * ~ 第一个 * 代表任意修饰符及任意返回值.
     * ~ 第二个 * 任意包名
     * ~ 第三个 * 代表任意方法.
     * ~ 第四个 * 定义在controller包或者子包
     * ~ 第五个 * 任意方法
     * ~ .. 匹配任意数量的参数.
     * </pre>
     */
    @Pointcut(value = "execution(public * com.dx..*.rest..*.*(..)) " +
            "||execution(public * com.dx..*.controller..*.*(..))")
    public void webLog() {
    }

    /**
     * 在切点之前织入
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        startTime = System.currentTimeMillis();
        String traceId = UUID.randomUUID().toString();
        MDC.put(AdminConstant.LOG_TRACE_ID,traceId);

        // 打印请求相关参数
        log.info("########################## 开始请求 ##########################");
        // 打印请求 url
        // Log.info("Request Time  : {}", LocalDateTime.now());
        log.info("URL           : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.info("HTTP Method   : {}", request.getMethod());
        log.info("日志链路追踪id   : {}", traceId);
        // 打印调用 controller 的全路径以及执行方法
        /*Log.info("Class Method  : {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());*/
        // 打印请求的 IP
        // Log.info("IP            : {}", WebTool.getIpAddress(request));
        // 打印请求入参

        Object[] args = joinPoint.getArgs();
        Object[] arguments = new Object[args.length];
        for (int i = 0, len = args.length; i < len; i++) {
            if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) {
                continue;
            }
            arguments[i] = args[i];
        }
        String parameter = "";
        try {
            //接收请求参数 @RequestParam(value="files") MultipartFile[] files 转换会报错
            if(!request.getRequestURL().toString().contains("batchTerminate")){
                parameter = JsonTOUtils.toJson(arguments);
            }
        } catch (Exception e) {
            log.error("请求入参打印异常",e);
        }
        if(!request.getRequestURL().toString().contains("getInfoByIdCard")){

            log.info("请求参数:{}", parameter);
        }
    }


    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        endTime = System.currentTimeMillis();
        // Log.info("结束时间:{}", LocalDateTime.now());
        // 打印出参
        // Log.debug("响应参数:{}", JsonUtils.toJson(ret));
        log.debug("响应参数:{}", JsonTOUtils.toJson(ret));
        // 执行耗时
        log.info("处理耗时:{} ms", endTime - startTime);
        //MDC.remove(AdminConstant.LOG_TRACE_ID);
        log.info("########################## 结束请求 ##########################\n");
    }


}
